﻿using BZ.Core;
using HalconDotNet;
using SRDLL;
using System;
using System.Collections.Concurrent;
using System.Runtime.InteropServices;
using System.Threading;

namespace NDK.AcqDevice
{
    public class SRControllerBP : ILineLaser
    {
        private HImage heightImage;
        private HImage luminanceImage;
        private AutoResetEvent heightImageEvent = new AutoResetEvent(false);
        private AutoResetEvent luminanceImageEvent = new AutoResetEvent(false);
        public ConcurrentQueue<HImage> CQueneHeightImage { get; set; }

        int _currentDeviceId = 0;
        /********回调***********/
        private HighSpeedDataCallBack _callback;       //回调
        static int m_curBatchNo = 0;                   //回调函数中用到--当前批处理行数编号
        static int m_BatchWidth = 0;                   //回调中轮廓宽度
        static int BatchCallBackPoint = 0;             //回调中当前批处理总行数
        static uint[] EncoderDataCall = new uint[15000 * 2];         //回调编码器数据缓存
        byte[] GrayData = null;         //灰度数据缓存
        uint[] EncoderData = null;      //编码器数据缓存

        int m_DataWidth = 3200;         //轮廓宽度
        double m_XPitch = 0.02;         //X方向间距

        static int[] HeightData = null;        //高度数据缓存
        int[] TmpBuffer = null;       //中间缓存
        byte[] TmpGrayBuffer = null;
        uint[] TmpEncoderBuffer = null;

        int Max_col_Rool = 1000;   //有限循环单次获取最大行数 
        private bool b_MemoryErr;
        public bool IsIOTrigger { get; set; } = false;

        public HImage HeightImage(int timeout = 3000)
        {
            if (heightImageEvent.WaitOne(timeout) == true)
            {
                if (heightImage != null && heightImage.IsInitialized())
                {
                    return heightImage.CopyImage();
                }
                else
                {
                    return null;
                }
            }

            return null;
        }
        public HImage LuminanceImage(int timeout = 3000)
        {
            if (luminanceImageEvent.WaitOne(timeout) == true)
            {
                if (luminanceImage.IsInitialized())
                {
                    return luminanceImage.CopyImage();
                }
            }
            return null;
        }
        public bool IsConnected
        {
            get
            {
                int RT = SR7LinkFunc.SR7IF_GetOnlineCameraB(_currentDeviceId);
                if (RT == 0)
                    return true;
                else
                    return false;
            }
        }

        /// <summary>
        /// 连接传感器并初始化，可以通过IP或则SN连接
        /// </summary>
        /// <param name="id">传感器的唯一标识：IP或则SN，推荐用SN</param>
        /// <returns></returns>
        public bool Connect(string id, int portID)
        {
            SR7IF_ETHERNET_CONFIG _ethernetConfig = new SR7IF_ETHERNET_CONFIG();

            _callback = new HighSpeedDataCallBack(ReceiveHighSpeedData);
            try
            {
                if (id.Contains("."))
                {
                    string[] ips = id.Split('.');
                    _ethernetConfig.abyIpAddress = new Byte[]
                     {
                        Convert.ToByte(ips[0]),
                        Convert.ToByte(ips[1]),
                        Convert.ToByte(ips[2]),
                        Convert.ToByte(ips[3])
                     };
                }

                int Rc = SR7LinkFunc.SR7IF_EthernetOpen(_currentDeviceId, ref _ethernetConfig);
                if (Rc == 0)
                {
                    uint dwProfileCnt = Convert.ToUInt32(10);
                    int reT = SR7LinkFunc.SR7IF_HighSpeedDataEthernetCommunicationInitalize(_currentDeviceId,
                    ref _ethernetConfig,
                    0,
                    _callback,
                    dwProfileCnt,
                    0);
                    if (reT < 0)
                    {
                        throw new LaserException("高速数据以太网通信初始化失败! 返回值:" + reT);
                    }
                    return true;
                }
            }
            catch (Exception ex)
            {
                throw new LaserException("SR Connect Exception! StackTrace:" + ex.StackTrace);
            }
            return false;
        }


        public void DisConnect()
        {
            //批处理停止
            int Rc = SR7LinkFunc.SR7IF_StopMeasure(_currentDeviceId);
            if (Rc != 0)
                throw new LaserException("停止批处理失败,返回值" + Rc);

            //关闭设备
            int reT = SR7LinkFunc.SR7IF_CommClose(_currentDeviceId);
            if (reT < 0)
                throw new LaserException("设备关闭失败,返回值" + reT);

        }
        /// <summary>
        /// 触发，开始采集
        /// </summary>
        /// <returns></returns>
        public bool Start()
        {

            try
            {
                try
                {
                    HeightData = new int[15000 * 6400];
                    GrayData = new byte[15000 * 6400];
                    EncoderData = new uint[15000 * 2];

                    TmpBuffer = new int[Max_col_Rool * 6400];       //中间缓存
                    TmpGrayBuffer = new byte[Max_col_Rool * 6400];
                    TmpEncoderBuffer = new uint[Max_col_Rool * 2];

                    for (int i = 0; i < HeightData.Length; i++)
                    {
                        HeightData[i] = -1000000;
                    }
                }
                catch (Exception e)
                {
                    b_MemoryErr = true;
                    throw new LaserException("内存申请失败! StackTrace:" + e.StackTrace);
                }
                //开始批处理
                int Rc = -1;
                if (IsIOTrigger)
                    Rc = SR7LinkFunc.SR7IF_StartIOTriggerMeasure(_currentDeviceId, 20000, 0);
                else
                    Rc = SR7LinkFunc.SR7IF_StartMeasure(_currentDeviceId, 20000);

                if (Rc < 0)
                {
                    throw new LaserException("批处理操作失败! 返回值:" + Rc.ToString());

                }

                // 获取批处理总行数
                IntPtr DataObject = new IntPtr();
                //int TempBatchPoint = SR7LinkFunc.SR7IF_ProfilePointSetCount(_currentDeviceId, DataObject);

                // 获取轮廓宽度
                m_DataWidth = SR7LinkFunc.SR7IF_ProfileDataWidth(_currentDeviceId, DataObject);

                // 数据x方向间距(mm)
                m_XPitch = SR7LinkFunc.SR7IF_ProfileData_XPitch(_currentDeviceId, DataObject);

            }
            catch (Exception ex)
            {
                throw new LaserException("SR Trigger Exception! StackTrace:" + ex.StackTrace);
            }
            return true;
        }
        /// <summary>
        /// 停止触发
        /// </summary>
        /// <returns></returns>
        public bool Stop()
        {

            try
            {
                int Rc = SR7LinkFunc.SR7IF_StopMeasure(_currentDeviceId);
                if (Rc != 0)
                {
                    throw new LaserException("SR Stop Fail! return:" + Rc);
                }
            }
            catch (Exception ex)
            {
                throw new LaserException("SR Stop Exception! StackTrace:" + ex.StackTrace);
            }
            return true;
        }
        /// <summary>
        /// 停止采集高度图，当长时间没有高度图像返回时，可调用此方法结束等待
        /// </summary>
        /// <returns></returns>
        public bool StopAcqHeightImage()
        {
            heightImageEvent.Set();
            return Stop();
        }
        /// <summary>
        /// 停止采集亮度图，当长时间没有亮度图像返回时，可调用此方法结束等待
        /// </summary>
        /// <returns></returns>
        public bool StopAcqLuminanceImage()
        {
            luminanceImageEvent.Set();
            return Stop();
        }
        /// <summary>
        /// 加载Job
        /// </summary>
        /// <param name="name">Job号</param>
        /// <returns></returns>
        public bool SwitchJob(string no)
        {

            try
            {
                int PRGNo = Convert.ToInt32(no);
                int reT = SR7LinkFunc.SR7IF_SwitchProgram(_currentDeviceId, PRGNo);
                if (reT < 0)
                    throw new LaserException("SR SwitchJob Fail! Return:" + reT);
            }
            catch (Exception ex)
            {
                throw new LaserException("SR SwitchJob Exception! StackTrace:" + ex.StackTrace);
            }
            return true;
        }

        public void LMIChangeScanLength(double length)
        {
            return;
        }

        /// <summary>
        /// 回调接受数据
        /// </summary>
        /// <param name="buffer"></param>         指向储存概要数据的缓冲区的指针.
        /// <param name="size"></param>           每个单元(行)的字节数量.
        /// <param name="count"></param>          存储在pBuffer中的内存的单元数量.
        /// <param name="notify"></param>         中断或批量结束等中断的通知.
        /// <param name="user"></param>           用户自定义信息.
        public void ReceiveHighSpeedData(IntPtr buffer, uint size, uint count, uint notify, uint user)
        {
            if (notify != 0)
            {
                if (Convert.ToBoolean(notify & 0x08))
                {
                    SR7LinkFunc.SR7IF_StopMeasure(_currentDeviceId);
                }
            }


            if (count == 0 || size == 0)
                return;

            if (b_MemoryErr)
            {
                return;
            }

            uint profileSize = (uint)(size / Marshal.SizeOf(typeof(int)));   //轮廓宽度

            // 获取批处理总行数
            IntPtr DataObject = new IntPtr();
            int TempBatchPoint = SR7LinkFunc.SR7IF_ProfilePointSetCount(_currentDeviceId, DataObject);
            BatchCallBackPoint = TempBatchPoint;
            m_BatchWidth = Convert.ToInt32(profileSize);


            //数据拷贝
            int[] bufferArray = new int[profileSize * count];
            Marshal.Copy(buffer, bufferArray, 0, (int)(profileSize * count));
            int TmpNum = Convert.ToInt32(m_curBatchNo * profileSize);
            if (m_curBatchNo < BatchCallBackPoint)
            {
                if (m_curBatchNo + count > BatchCallBackPoint)
                {
                    int TmpCount = BatchCallBackPoint - m_curBatchNo;
                    Array.Copy(bufferArray, 0, HeightData, TmpNum, profileSize * TmpCount);

                }
                else
                {
                    Array.Copy(bufferArray, 0, HeightData, TmpNum, profileSize * Convert.ToInt32(count));
                }
            }

            m_curBatchNo += Convert.ToInt32(count);


            if (notify != 0)
            {
                if (notify == 0x10000)
                {
                    SR7LinkFunc.SR7IF_StopMeasure(_currentDeviceId);
                    System.Console.Write("数据接收完成!\n");
                    using (PinnedObject pin = new PinnedObject(HeightData))
                    {
                        IntPtr bufferPointer = pin.Pointer;

                        heightImage = new HImage();
                        heightImage.GenImage1("int4", (int)m_BatchWidth, (int)m_curBatchNo, bufferPointer);
                        heightImage = heightImage.ConvertImageType("real");
                        heightImage = heightImage.ScaleImage(1 / 100000.0, 0);
                    }
                    m_curBatchNo = 0;
                    heightImageEvent.Set();

                }
                if (Convert.ToBoolean(notify & 0x80000000))
                {
                    System.Console.Write("批处理重新开始!\n");
                    m_curBatchNo = 0;
                }

                if (Convert.ToBoolean(notify & 0x04))
                {
                    System.Console.Write("新批处理!\n");
                }
            }
        }



        public bool SDKToHalconImage(HObject Image, HTuple YResolution, HTuple XResolution, HTuple ZResolution, HTuple ZOffset, out HImage outImage)
        {
            try
            {
                HTuple hv_HomMat2DIdentity = new HTuple(), hv_HomMat2DScale = new HTuple();
                HObject ho_Image1, ho_ImageScaled;
                HObject ho_ImageScaled1, ho_ImageConverted;
                hv_HomMat2DIdentity.Dispose();
                HOperatorSet.HomMat2dIdentity(out hv_HomMat2DIdentity);
                using (HDevDisposeHelper dh = new HDevDisposeHelper())
                {
                    hv_HomMat2DScale.Dispose();
                    if (YResolution > XResolution)
                    {
                        HOperatorSet.HomMat2dScale(hv_HomMat2DIdentity, 1, YResolution / XResolution, 0, 0, out hv_HomMat2DScale);
                    }
                    else
                    {
                        HOperatorSet.HomMat2dScale(hv_HomMat2DIdentity, YResolution / XResolution, 1, 0, 0, out hv_HomMat2DScale);
                    }
                }
                HOperatorSet.AffineTransImage(Image, out ho_Image1, hv_HomMat2DScale, "constant", "true");

                using (HDevDisposeHelper dh = new HDevDisposeHelper())
                {
                    HOperatorSet.ScaleImage(ho_Image1, out ho_ImageScaled, 1, -ZOffset);
                }
                using (HDevDisposeHelper dh = new HDevDisposeHelper())
                {
                    HOperatorSet.ScaleImage(ho_ImageScaled, out ho_ImageScaled1, 1 / ZResolution, 32768);
                }
                HOperatorSet.ConvertImageType(ho_ImageScaled1, out ho_ImageConverted, "uint2");
                outImage = new HImage(ho_ImageConverted);
            }
            catch (Exception)
            {
                outImage = new HImage();
            }

            return true;
        }

    }
}
